/*
 * Copyright (c) 2016 moondev.cn
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.moondev.moonlog.delegate;

import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import cn.moondev.moonlog.delegate.utils.Identities;
import org.slf4j.MDC;

/**
 * 创建自定义格式转换符：利用threadLocal来打印当前请求的唯一序列号<BR>
 * 创建原理：首先,必须继承 ClassicConverter 类。
 * ClassicConverter 对象负责从 ILoggingEvent 提取信息,并产生一个字符串。
 * 例如,LoggerConverter,它是处理“%logger”转换符的转换器,它从 ILoggingEvent 提取 logger 的名字并作为字符串返回。
 * LogMsgNoConverter就是处理%msgno转换符的转换器了，它为每个想线程增加一个唯一序列号，用于追踪当前线程的执行信息。
 * <h1>附MDC简介：</h1>
 * MDC：映射诊断环境<BR>
 * MDC 类只有静态方法,开发者可以把信息放进一个诊断环境,之后用其他 logback 组件获取这些信息。
 * MDC 是基于每个线程进行管理的。子线程自动继承其父的映射诊断环境的一个副本。
 * 典型地,当开始为新的客户端请求服务时,开发者会向 MDC 里插入恰当的环境信息,比如客户端 id、客户端 IP 地址、请求参数等等。
 * Logback 组件会自动在每个记录条目里包含这些信息
 *
 * @author CHEN(luecsc@sina.com)
 * @version 1.0.1
 * @date 16-1-22
 * @since 1.0.1
 */
public class LogMsgNoConverter extends ClassicConverter {

    public static final String MSGNO_NAME = "msgno";

    @Override
    public String convert(ILoggingEvent event) {
        String msgno = null;
        if (event.getMDCPropertyMap() != null) {
            msgno = event.getMDCPropertyMap().get(MSGNO_NAME);
        }
        if (msgno != null && !msgno.isEmpty()) {
            return msgno;
        }
        return getCurrentMsgno();
    }

    public static void setMsgno(String msgnoStr) {
        String msgno = msgnoStr;
        if (msgno == null || msgno.isEmpty()) {
            msgno = getCurrentMsgno();
        } else {
            MDC.put(MSGNO_NAME, msgno);
        }
    }

    public static void clear() {
        MDC.remove(MSGNO_NAME);
    }

    public static String getCurrentMsgno() {
        String msgno = MDC.get(MSGNO_NAME);
        if (msgno == null || msgno.isEmpty()) {
            msgno = Identities.uuid2();
            MDC.put(MSGNO_NAME, msgno);
        }
        return msgno;
    }
}